import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class EbhackFrontend {
	private static JFrame mainWindow;
	
	public static void main(String[] args) {
		createGUI();
		show();
	}
  
	public static void createGUI() {
		mainWindow = new JFrame();
		mainWindow.setTitle("EbHack Frontend");
		mainWindow.getContentPane().setLayout(new BorderLayout(10,10));
		
		FileField exe = new FileField(true, false);
		FileField importROM = new FileField(true, false);
		FileField importDir = new FileField(false, true);
		FileField exportDir = new FileField(false, true);
		FileField exportCleanROM = new FileField(true, false);
		FileField exportROM = new FileField(true, false);
		
		JTextArea console = new JTextArea(9, 40);
		JScrollPane scrollPane = new JScrollPane(console);
		
		JButton importButton = new JButton("Import");
		JButton exportButton = new JButton("Export");
		
		ButtonListener bl = new ButtonListener(importROM,
				importDir, exportDir, exportCleanROM, exportROM,
				exe, console, importButton, exportButton);
		
		importButton.setAlignmentX(Component.CENTER_ALIGNMENT);
		importButton.setActionCommand("import");
		importButton.addActionListener(bl);
		exportButton.setActionCommand("export");
		exportButton.addActionListener(bl);
		exportButton.setAlignmentX(Component.CENTER_ALIGNMENT);
		
		JTabbedPane tabbedPane = new JTabbedPane();
		JPanel importPanel = new JPanel();
		importPanel.setLayout(new BoxLayout(importPanel, BoxLayout.Y_AXIS));
		importPanel.add(getLabeledComponent("Clean ROM: ", importROM.getPanel(), "Input ROM"));
		importPanel.add(getLabeledComponent("Output Directory: ", importDir.getPanel(), "Output Directory"));
		importPanel.add(importButton);
		tabbedPane.addTab("Import", importPanel);
		JPanel exportPanel = new JPanel();
		exportPanel.setLayout(new BoxLayout(exportPanel, BoxLayout.Y_AXIS));
		exportPanel.add(getLabeledComponent("Directory: ", exportDir.getPanel(), "Input Directory"));
		exportPanel.add(getLabeledComponent("Clean ROM: ", exportCleanROM.getPanel(), "Clean ROM"));
		exportPanel.add(getLabeledComponent("Output ROM: ", exportROM.getPanel(), "Output ROM"));
		exportPanel.add(exportButton);
		tabbedPane.addTab("Export", exportPanel);
		
		mainWindow.add(getLabeledComponent("EBhack Executable: ", exe.getPanel(), "EBHack Executable"),
				BorderLayout.PAGE_START);
		mainWindow.add(tabbedPane, BorderLayout.CENTER);
		mainWindow.add(scrollPane, BorderLayout.PAGE_END);
		
        mainWindow.invalidate();
        mainWindow.setLocationByPlatform(true);
        mainWindow.validate();
        mainWindow.setResizable(false);
		
		mainWindow.pack();
		
	    mainWindow.addWindowListener(new WindowListener() {

	          public void windowClosing(WindowEvent e) {
	             System.exit(0);
	          }
	          public void windowClosed(WindowEvent e) { }
	          public void windowIconified(WindowEvent e) { }
	          public void windowDeiconified(WindowEvent e) { }
	          public void windowOpened(WindowEvent e) { }
	          public void windowActivated(WindowEvent e) { }
	          public void windowDeactivated(WindowEvent e) { }
	       });
		
		mainWindow.setVisible(true);
	}
	
	public static void show() {
		mainWindow.setVisible(true);
	}
	
	public static class ButtonListener implements ActionListener {
		private FileField importROM, importDir, exportDir, exportCleanROM, exportROM, exe;
		private JTextArea console;
		private JButton importButton, exportButton;
		private boolean running = false;
		
		public ButtonListener(FileField importROM, FileField importDir,
				FileField exportDir, FileField exportCleanROM,
				FileField exportROM, FileField exe, JTextArea console,
				JButton importButton, JButton exportButton) {
			this.importROM = importROM;
			this.importDir = importDir;
			this.exportDir = exportDir;
			this.exportCleanROM = exportCleanROM;
			this.exportROM = exportROM;
			this.exe = exe;
			this.console = console;
			this.importButton = importButton;
			this.exportButton = exportButton;
		}
		
		private void updateTextArea(final String text) {
			    SwingUtilities.invokeLater(new Runnable() {
			      public void run() {
			        console.append(text);
			        console.append("\n");
			      }
			    });
		}
		
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("import") || e.getActionCommand().equals("export")) {
				console.setText("");
				SwingWorker<String, Void> worker;
				if (e.getActionCommand().equals("import")) {
					worker = new SwingWorker<String, Void>() {
						public String doInBackground() {
							try {
							Runtime r = Runtime.getRuntime();
							String[] cmd;
							
							cmd = new String[] { 
								exe.getFilename(), "import", importROM.getFilename(),
								importDir.getFilename() };
							Process p;
							p = r.exec(cmd);
							
							BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream( new 
			                                               BufferedInputStream(p.getInputStream()))));
							String lineRead = null;
							while( (lineRead = reader.readLine() ) != null) {
								console.append(lineRead);
								console.append("\n");
								console.setCaretPosition(console.getDocument().getLength()-1);
							}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							return "";
						}
					};
					worker.execute();
				} else {
					worker = new SwingWorker<String, Void>() {
						public String doInBackground() {
							try {
							Runtime r = Runtime.getRuntime();
							String[] cmd;
							
							cmd = new String[] { 
								exe.getFilename(), "export", exportDir.getFilename(),
								exportCleanROM.getFilename(), exportROM.getFilename() };
							Process p;
							p = r.exec(cmd);
							
							BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream( new 
			                                               BufferedInputStream(p.getInputStream()))));
							String lineRead = null;
							while( (lineRead = reader.readLine() ) != null) {
								console.append(lineRead);
								console.append("\n");
								console.setCaretPosition(console.getDocument().getLength()-1);
							}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							return "";
						}
					};
					worker.execute();
				}
				running = false;
			}
		}
	}
	
	public static class FileField implements ActionListener {
		private JTextField tf;
		private JButton b;
		private JPanel panel;
		private JFileChooser fc;
		
		public FileField(boolean files, boolean folders) {
			tf = new JTextField(30);
			b = new JButton("Browse...");
			b.addActionListener(this);
			fc = new JFileChooser();
			if (files && folders)
				fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
			else if (folders)
				fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			else
				fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
			
			panel = pairComponents(tf, b, true, "Select a file");
		}
		
		public JPanel getPanel() {
			return panel;
		}
		
		public String getFilename() {
			return tf.getText();
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			int returnVal = fc.showOpenDialog(b);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				tf.setText(fc.getSelectedFile().getAbsolutePath());
			}
		}
	}
	
    public static JPanel getLabeledComponent(String label, JComponent comp,
            String tooltip) // useful for making layouts
        {
            JLabel l = new JLabel(label);
            l.setLabelFor(comp);
            return pairComponents(l, comp, true, tooltip);
        }
    
    public static JPanel pairComponents(JComponent comp1, JComponent comp2,
            boolean isHorizontal, String tooltip)
        {
            return pairComponents(comp1, comp2, isHorizontal, false, tooltip,
                tooltip);
        }

    public static JPanel pairComponents(JComponent comp1, JComponent comp2,
            boolean isHorizontal, boolean stretch, String tooltip1, String tooltip2)
        {
            JPanel out = new JPanel();
            out.setLayout(new BorderLayout());
            if (comp1 == null)
                comp1 = new JLabel();
            if (comp2 == null)
                comp2 = new JLabel();
            comp1.setMaximumSize(comp1.getPreferredSize());
            if (tooltip1 != null)
            {
                comp1.setToolTipText(tooltip1);
            }
            out.add(comp1, (isHorizontal ? BorderLayout.WEST : BorderLayout.NORTH));
            comp2.setMaximumSize(comp2.getPreferredSize());
            if (tooltip2 != null)
            {
                comp2.setToolTipText(tooltip2);
            }
            out.add(comp2, (stretch ? BorderLayout.CENTER : (isHorizontal
                ? BorderLayout.EAST
                : BorderLayout.SOUTH)));
            return out;
        }

}